import time
import re

class tld_parser:
  """template tld parser / metaclass"""
  _whois_raw_response = None
  _regex = None
  _not_found_message = None
  _fqdn = None

  def __init__(self, response, fqdn):
    """class initiator"""
    self._fqdn = fqdn
    self._whois_raw_response = response
    # check for nonexisting domain
    if self._not_found_message != None and len(re.findall(self._not_found_message, self._whois_raw_response)) > 0:
      raise ValueError("This domain '" + fqdn + "' not found based on the whois response")
    
  def __getattr__(self, attr):
    """The first time an attribute is called it will be calculated here.
    The attribute is then set to be accessed directly by subsequent calls.
    """
    whois_regex = self._regex.get(attr)
    if whois_regex:
      setattr(self, attr, re.findall(whois_regex, self._whois_raw_response))

      # cast date fields as datetime tuple and return those as datetime tuple lists
      try:
	if attr == "expiration_date" or attr == "issue_date":
	  if not len(getattr(self, attr)) > 0:
	    raise ValueError("Failed to parse this argument '" + attr + "' from whois reply")
	  else:
	    # return list instance of the parameter
	    newdates = []
	    for datestring in getattr(self, attr):
	      if datestring.strip() != "":
		newdates.append(self._cast_date(datestring))
	    return newdates
      except:
	raise

      # return the argument requested
      if not len(getattr(self, attr)) > 0:
	raise ValueError("Failed to parse this argument '" + attr + "' from whois reply")
      else:
	# return cleaned values only in the array
	stripped = []
	for tostrip in getattr(self, attr):
	  if tostrip.strip() != "":
	    stripped.append(tostrip.strip())
	return stripped
    else:
      # or raise error if no regexp was specified for this info in this tld
      raise KeyError('Unknown attribute: %s' % attr)

  def _cast_date(self, date_str):
    """Convert any date string found in WHOIS to a time object."""
    known_formats = [
      '%d.%m.%Y', # 02.02.2000
      '%d-%b-%Y', # 02-jan-2000
      '%Y-%m-%d', # 2000-01-02
      '%Y.%m.%d', # 2000.01.02
      '%d-%b-%Y %H:%M:%S %Z', # 24-Jul-2009 13:20:03 UTC
      '%a %b %d %H:%M:%S %Z %Y', # Tue Jun 21 23:59:59 GMT 2011
      '%Y-%m-%dT%H:%M:%SZ', # 2007-01-26T19:10:31Z
    ]

    for format in known_formats:
      try:
	return time.strptime(date_str.strip(), format)
      except ValueError, e:
	pass # Wrong format, keep trying

    raise ValueError("No matching date format found for '" + date_str + "'")
    return None

#eof